import {
  scene
} from '../scene/index'
import Cuboid from '../block/cuboid'
import Cylinder from '../block/cylinder'

// ground 是实例化以后
import ground from '../objects/ground'
import bottle from '../objects/bottle'

import blockConf from '../../confs/block-conf'
import gameConf from '../../confs/game-conf'
import bottleConf from '../../confs/bottle-conf'

import utils from '../utils/index'
import ScoreText from '../view3d/scoreText'

import audioManager from '../modules/audio-manager.js'

import { stopAllAnimation } from '../../libs/animation'

const HIT_NEXT_BLOCK_CENTER = 1
const HIT_CURRENT_BLOCK = 2
const GAME_OVER_NEXT_BLOCK_BACK = 3
const GAME_OVER_CURRENT_BLOCK_BACK = 4
const GAME_OVER_NEXT_BLOCK_FRONT = 5
// 两种碰撞检测同时触发
const GAME_OVER_BOTH = 6
// 跳到下个block没有到center（一般跳跃）
const HTI_NEXT_BLOCK_NORMAL = 7

export default class GamePage {


  constructor(callbacks) {
    this.callbacks = callbacks
    this.state = 'stop'
    this.checkingHit = false
    this.targetPosition = {}
    this.axis = null
    this.combo = 0;
  }

  init() {
    // 测试 mvc 页面初始化
    // this.rotateTriangle()

    // console.log("init game page")
    this.score = 0
    this.scoreText = new ScoreText()
    this.scoreText.init({
      fillStyle: 0x666699
    })

    this.scene = scene
    this.ground = ground
    this.bottle = bottle

    this.scene.init()
    this.ground.init()
    this.bottle.init()


    this.render()
    // 加载block
    this.addInitBlock()
    this.addGround()
    this.addBottle()
    this.addHelper()
    this.addScore()


    // 绑定touch事件
    // this.bindTouchEvent()
  }

  /**
   * 清空场景中元素
   */
  deleteObjectsFromScene() {
    let obj = this.scene.instance.getObjectByName('block')
    while (obj) {
      this.scene.instance.remove(obj)
      if (obj.geometry) {
        obj.geometry.dispose()
      }
      if (obj.material) {
        obj.material.dispose()
      }
      obj = this.scene.instance.getObjectByName('block')
    }
    this.scene.instance.remove(this.bottle.obj)
    this.scene.instance.remove(this.ground.instance)
  }

  show() {
    this.visible = true
  }

  hide() {
    this.visible = false
  }

  restart() {
    console.log("game page restart")
    // 分数初始置0
    this.score = 0
    this.combo = 0;
    this.updateScore(this.score)
    this.deleteObjectsFromScene()

    //  场景和 bottle 重置
    this.scene.reset()
    this.bottle.reset()

    // this.updateScore(0)
    this.addInitBlock()
    this.addGround()
    this.addBottle()
    this.bindTouchEvent()
  }

  render() {
    if (this.currentBlock) {
      this.currentBlock.update()
    }
    if (this.bottle) {
      this.bottle.update()
    }
    // 校验碰撞状态
    this.checkBottleHit()
    if (this.visible) {
      this.scene.render()
    }
    // windows 下挂载对象, 这里调用动画
    requestAnimationFrame(this.render.bind(this))
  }

  addInitBlock() {
    this.currentBlock = new Cuboid(-15, 0, 0, 'show','color')
    this.scene.instance.add(this.currentBlock.instance)
    this.nextBlock = new Cylinder(23, 0, 0, 'show', 'color')
    this.scene.instance.add(this.nextBlock.instance)
    const initDirection = 0
    this.targetPosition = {
      x: 23,
      y: 0,
      z: 0
    }
    this.setDirection(initDirection)
  }

  /**
   * 生成下一个block 同时改变相机位置
   */
  updateNextBlock() {
    const seed = Math.round(Math.random())
    const type = seed ? 'cuboid' : 'cylinder'
    const direction = Math.round(Math.random()) // 0 -> x 1 -> z
    const width = Math.round(Math.random() * 12) + 8
    const distance = Math.round(Math.random() * 20) + 20
    this.currentBlock = this.nextBlock
    const targetPosition = this.targetPosition = {}
    if (direction == 0) { // x
      targetPosition.x = this.currentBlock.instance.position.x + distance
      targetPosition.y = this.currentBlock.instance.position.y
      targetPosition.z = this.currentBlock.instance.position.z
    } else if (direction == 1) { // z
      targetPosition.x = this.currentBlock.instance.position.x
      targetPosition.y = this.currentBlock.instance.position.y
      targetPosition.z = this.currentBlock.instance.position.z - distance
    }
    this.setDirection(direction)
    if (type == 'cuboid') {
      const seed = Math.floor(Math.random() * 2)
      let name
      switch (seed) {
        case 0:
          name = 'well'
          break
        case 1:
          name = 'color'
          break
      }
      this.nextBlock = new Cuboid(targetPosition.x, targetPosition.y, targetPosition.z, 'popup', name, width)
    } else if (type == 'cylinder') {
      this.nextBlock = new Cylinder(targetPosition.x, targetPosition.y, targetPosition.z, 'popup', 'color',width)
    }
    // this.nextBlock.instance.position.set(targetPosition.x, targetPosition.y, targetPosition.z)
    this.scene.instance.add(this.nextBlock.instance)
    // camera 始终看向nextBlock 中心位置
    const cameraTargetPosition = {
      x: (this.currentBlock.instance.position.x + this.nextBlock.instance.position.x) / 2,
      y: (this.currentBlock.instance.position.y + this.nextBlock.instance.position.y) / 2,
      z: (this.currentBlock.instance.position.z + this.nextBlock.instance.position.z) / 2,
    }
    this.scene.updateCameraPosition(cameraTargetPosition)
    // 展示阴影
    this.ground.updatePosition(cameraTargetPosition)
  }

  /**
   * 更新分数
   */
  updateScore(score) {
    this.scoreText.updateScore(score)
    // this.scene.updateScore(this.scoreText.instance)
  }

  setDirection(direction) {
    const currentPosition = {
      x: this.bottle.obj.position.x,
      z: this.bottle.obj.position.z
    }
    this.axis = new THREE.Vector3(this.targetPosition.x - currentPosition.x, 0, this.targetPosition.z - currentPosition.z)
    this.axis.normalize()
    this.bottle.setDirection(direction, this.axis)
  }

  addGround() {
    this.scene.instance.add(this.ground.instance)
  }

  addBottle() {
    this.scene.instance.add(this.bottle.obj)
    this.bottle.showup()
  }

  addHelper() {
    this.axesHelper = new THREE.AxesHelper(100)
    this.scene.instance.add(this.axesHelper)
  }

  // 将score 加到场景
  addScore() {
    this.scene.addScore(this.scoreText.instance)
  }

  bindTouchEvent() {
    console.log('bind touch event')
    canvas.addEventListener('touchstart', this.touchStartCallback)
    canvas.addEventListener('touchend', this.touchEndCallback)
  }

  removeTouchEvent() {
    console.log('remove touch event')
    canvas.removeEventListener('touchstart', this.touchStartCallback)
    canvas.removeEventListener('touchend', this.touchEndCallback)
  }

  touchStartCallback = (e) => {
    this.touchStartTime = Date.now()
    this.state = 'prepare'
    this.bottle.shrink()
    this.currentBlock.shrink()
    // 播放收缩音乐
    audioManager.shrink.play()
  }

  touchEndCallback = (e) => {
    this.touchEndTime = Date.now()
    const duration = this.touchEndTime - this.touchStartTime
    // 设置初速度
    this.bottle.velocity.vx = Math.min(duration / 6, 400)
    this.bottle.velocity.vx = +this.bottle.velocity.vx.toFixed(2)
    this.bottle.velocity.vy = Math.min(150 + duration / 20, 400)
    this.bottle.velocity.vy = +this.bottle.velocity.vy.toFixed(2)
    this.state = 'jump'
    this.hit = this.getHitStatus(this.bottle, this.currentBlock, this.nextBlock, blockConf.height / 2 - (1 - this.currentBlock.instance.scale.y) * blockConf.height)
    this.checkingHit = true
    this.currentBlock.rebound()
    this.bottle.rotate()
    this.bottle.jump(duration)
    // this.updateNextBlock()

    audioManager.shrink.stop()
    audioManager.shrink_end.stop()
  }

  /**
   * 校验是否到飞行时间
   * 校验hit状态 是否需要触发后续动画
   */
  checkBottleHit() {
    if (this.checkingHit && this.bottle.obj.position.y <= blockConf.height / 2 + 0.1 && this.bottle.status === 'jump' && this.bottle.flyingTime > 0.3) {
      this.checkingHit = false
      console.log(this.hit)
      if (this.hit == HIT_NEXT_BLOCK_CENTER || this.hit == HTI_NEXT_BLOCK_NORMAL || this.hit == HIT_CURRENT_BLOCK) { // 游戏继续
        this.state = 'stop'
        this.bottle.stop()
        this.bottle.obj.position.y = blockConf.height / 2
        this.bottle.obj.position.x = this.bottle.destination[0]
        this.bottle.obj.position.z = this.bottle.destination[1]
        if (this.hit == HIT_NEXT_BLOCK_CENTER || this.hit == HTI_NEXT_BLOCK_NORMAL){
          if (this.hit == HIT_NEXT_BLOCK_CENTER){
            
            this.combo++
            audioManager['combo' + (this.combo <= 8 ? this.combo : '8')].play()
            this.score += 2 * this.combo
            // 展示分数动画
            // this.bottle.showAddScore(2 * this.combo)
            this.updateScore(this.score)
          } else if (this.hit == HTI_NEXT_BLOCK_NORMAL){
            this.combo = 0;
            audioManager.success.play()
            // this.bottle.showAddScore(1)
            // 更新分数
            this.updateScore(++this.score)
          }
          this.updateNextBlock()
        }
        
      } else { //游戏结束
        this.combo = 0
        this.state = 'over'
        this.removeTouchEvent()
        // 如果是从边缘掉落
        if(this.hit == GAME_OVER_NEXT_BLOCK_BACK || this.hit == GAME_OVER_CURRENT_BLOCK_BACK){
          // 1.停掉所有动画
          stopAllAnimation()
          // 2.bottle 位置更新停掉 stop
          this.bottle.stop()
          // 前倾
          this.bottle.forerake()
          audioManager.fall_from_block.play()
          this.bottle.obj.position.y = blockConf.height / 2

          setTimeout(() => {
            this.callbacks.showGameOverPage()
          }, 2000)
        }else if(this.hit == GAME_OVER_NEXT_BLOCK_FRONT){
          stopAllAnimation()
          this.bottle.stop()
          this.bottle.hypsokinesis()
          audioManager.fall_from_block.play()
          this.bottle.obj.position.y = blockConf.height / 2
          setTimeout(() => {
            this.callbacks.showGameOverPage()
          }, 2000)
        }else{
          audioManager.fall.play()
          this.callbacks.showGameOverPage()
        }
        
      }
    }
  }

  getHitStatus(bottle, currentBlock, nextBlock, initY) {

    // debugger
    var flyingTime = parseFloat(bottle.velocity.vy) / parseFloat(gameConf.gravity) * 2
    initY = initY || +bottle.obj.position.y.toFixed(2)
    var destinationY = blockConf.height / 2

    var differenceY = destinationY
    // var time = +((bottle.velocity.vy - Math.sqrt(Math.pow(bottle.velocity.vy, 2) - 2 * gameConf.gravity * differenceY)) / -gameConf.gravity).toFixed(2)
    var time = +((-bottle.velocity.vy + Math.sqrt(Math.pow(bottle.velocity.vy, 2) - 2 * gameConf.gravity * differenceY)) / -gameConf.gravity).toFixed(2)
    flyingTime -= time
    flyingTime = +flyingTime.toFixed(2)
    var destination = []
    var bottlePosition = new THREE.Vector2(bottle.obj.position.x, bottle.obj.position.z)
    var translate = new THREE.Vector2(this.axis.x, this.axis.z).setLength(bottle.velocity.vx * flyingTime)
    bottlePosition.add(translate)
    bottle.destination = [+bottlePosition.x.toFixed(2), +bottlePosition.y.toFixed(2)]
    destination.push(+bottlePosition.x.toFixed(2), +bottlePosition.y.toFixed(2))
    if (nextBlock) {
      var nextDiff = Math.pow(destination[0] - nextBlock.instance.position.x, 2) + Math.pow(destination[1] - nextBlock.instance.position.z, 2)
      var nextPolygon = nextBlock.getVertices()
      var result1
      if (utils.pointInPolygon(destination, nextPolygon)) {
        if (Math.abs(nextDiff) < 5) {
          return HIT_NEXT_BLOCK_CENTER
        } else {
          return HTI_NEXT_BLOCK_NORMAL
        }
      } else if (utils.pointInPolygon([destination[0] - bottleConf.bodyWidth / 2, destination[1]], nextPolygon) || utils.pointInPolygon([destination[0], destination[1] + bottleConf.bodyDepth / 2], nextPolygon)) {
        result1 = GAME_OVER_NEXT_BLOCK_FRONT
      } else if (utils.pointInPolygon([destination[0], destination[1] - bottleConf.bodyDepth / 2], nextPolygon) || utils.pointInPolygon([destination[0] + bottleConf.bodyDepth / 2, destination[1]], nextPolygon)) {
        result1 = GAME_OVER_NEXT_BLOCK_BACK
      }
    }

    var currentPolygon = currentBlock.getVertices()
    var result2
    // 判断点是否在多边形内
    if (utils.pointInPolygon(destination, currentPolygon)) {
      return HIT_CURRENT_BLOCK
    } else if (utils.pointInPolygon([destination[0], destination[1] + bottleConf.bodyDepth / 2], currentPolygon) || utils.pointInPolygon([destination[0] - bottleConf.bodyWidth / 2, destination[1]], currentPolygon)) {
      if (result1) return GAME_OVER_BOTH
      return GAME_OVER_CURRENT_BLOCK_BACK
    }
    return result1 || result2 || 0
  }

  rotateTriangle() {
    var width = window.innerWidth
    var height = window.innerHeight


    var renderer = new THREE.WebGLRenderer({
      canvas: canvas
    })
    var scene = new THREE.Scene()
    // 实现gameScence实例访问scence
    this.scene = scene
    var camera = new THREE.OrthographicCamera(-width / 2, width / 2,
      height / 2, -height / 2, -1000, 1000)

    // renderer.setClearColor(new THREE.Color(0x000000, 1.0))
    // 去掉透明度 颜色恢复正常
    renderer.setClearColor(new THREE.Color(0x000000))
    renderer.setSize(375, 667)

    var triangleShape = new THREE.Shape()
    triangleShape.moveTo(0, 100)
    triangleShape.lineTo(-100, -100)
    triangleShape.lineTo(100, -100)
    triangleShape.lineTo(0, 100)

    var geometry = new THREE.ShapeGeometry(triangleShape)
    var material = new THREE.MeshBasicMaterial({
      color: 0xff0000,
      side: THREE.DoubleSide
    })
    var mesh = new THREE.Mesh(geometry, material)
    this.mesh = mesh
    mesh.position.x = 0
    mesh.position.y = 0
    mesh.position.z = 1
    // 这里隐藏 gamePage 来调试gamePageOver
    scene.add(mesh)

    // 使用helper
    var axesHelper = new THREE.AxesHelper(100)
    scene.add(axesHelper)

    camera.position.x = 0
    camera.position.y = 0
    camera.position.z = 0
    camera.lookAt(new THREE.Vector3(0, 0, 1))

    var currentAngle = 0
    var lastTimestamp = Date.now()

    var animate = function() {
      var now = Date.now()
      var duration = now - lastTimestamp
      lastTimestamp = now
      currentAngle = currentAngle + duration / 1000 * Math.PI
    }


    // 游戏开始三秒后结束
    // gameController 中传入到gamePage 的callback 就会触发，即游戏结束callback会触发
    setTimeout(() => {
      // for(let i = 0; i< this.callbacks.length; i++){
      //   this.callbacks[i]()
      // }
      this.callbacks.showGameOverPage()
    }, 3000)

    var render = function() {
      animate()
      // mesh.rotation.set(0, 0, currentAngle)
      // 绕y轴
      mesh.rotation.set(0, currentAngle, 0)
      renderer.render(scene, camera)
      requestAnimationFrame(render)
    }

    render()
  }
}